#include "pool.h"
# include "../constant/constant.h"


ConnectionPool *ConnectionPool::pool = nullptr;
mutex ConnectionPool::checkMutex;

ConnectionPool *ConnectionPool::getInstance() {
    if (pool == nullptr) {
        checkMutex.lock();
        if (pool == nullptr) {
            pool = new ConnectionPool();
        }
        checkMutex.unlock();
    }
    return pool;
}



ConnectionPool::ConnectionPool() {
    for (int i = 0; i < CIVET_MYSQL_SIZE; i++) {
        auto* p_conn = new Connection();
        p_conn->refresh();
        queue_c.push(p_conn);
        count++;
    }

    thread produce([this] { produceConnection(); });
    produce.detach();
    thread scanner([this] { scannerConnection(); });
    scanner.detach();
}

shared_ptr<Connection> ConnectionPool::getConnection() {
    unique_lock<mutex> lock(lock_q);
    while (queue_c.empty()) {
        if (cv_status::timeout == cv.wait_for(lock, chrono::milliseconds(timeoutTime))) {
            LOG("获取连接失败...");
            return nullptr;
        }
    }

    shared_ptr<Connection> sp(queue_c.front(), [&](Connection *p_conn) {
        unique_lock<mutex> lock(lock_q);
        p_conn->refresh();
        queue_c.push(p_conn);
    });
    queue_c.pop();
    cv.notify_all();

    return sp;
}



void ConnectionPool::produceConnection() {
    for (;;) {
        unique_lock<mutex> lock(lock_q);
        while (!queue_c.empty()) {
            cv.wait(lock);
        }

        if (count < CIVET_MYSQL_MAX_SIZE) {
            auto* p_conn = new Connection();
            p_conn->refresh();
            queue_c.push(p_conn);
            count++;
        }
        cv.notify_all();
    }
}

void ConnectionPool::scannerConnection() {
    for (;;) {
        this_thread::sleep_for(chrono::seconds(CIVET_MYSQL_MAX_IDLE_TIME));
        unique_lock<mutex> lock(lock_q);
        while (count > CIVET_MYSQL_MAX_SIZE) {
            Connection *p = queue_c.front();
            if (p->timeout() >= (CIVET_MYSQL_MAX_IDLE_TIME * 1000)) {
                queue_c.pop();
                count--;
                delete p;
            } else {
                break;
            }
        }
    }
}